package de.awg.accountanalyzer.logic;

import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import de.awg.accountanalyzer.entities.Account;
import de.awg.accountanalyzer.entities.AccountPosition;
import de.awg.accountanalyzer.entities.Category;
import de.awg.accountanalyzer.entities.ChartEntity;

public class AccountManager {
	static Category INCOME_CATEGORY = null;
	static {
		INCOME_CATEGORY = new Category("Einnahmen");

	}

	/**
	 * Hierarchy Structure: Category |_Account |_AccountPosition
	 * 
	 * @param allPositions
	 * @return
	 */
	public static ObservableSet<ChartEntity> createCategories(Set<ChartEntity> allPositions) {
		ObservableSet<Category> categorySet = FXCollections.observableSet(new HashSet<Category>());
		// categorySet.add(INCOME_CATEGORY);

		// create categories and assign account positions
		for (ChartEntity element : allPositions) {
			AccountPosition position = (AccountPosition) element;
			Category category = getCategory(categorySet, position);

			if (category == null) {
				// create a new category
				category = new Category(position.getKreditor_Debitor());
			}
			
			if(!categorySet.contains(category));
			{
				categorySet.add(category);
			}

			Account account = getAccount(category.getAccountList(), position);
			// build the hierarchy
			account.addPosition(position);
			ListManager.getReference().addAccount(account);
			category.addAccount(account);
		}

		// remove categories with only 1 entry or empty name
		// and move their positions to "others" category
		ObservableSet<ChartEntity> finalCategorySet = FXCollections.observableSet(new TreeSet<ChartEntity>());
		Category othersCategory = null;
		for (Category category : categorySet) {
			Set<Account> accountList = category.getAccountList();
			if (accountList.size() == 1 || category.getCategoryName().isEmpty()) {
				if (othersCategory == null) {
					othersCategory = new Category("Allgemeine Positionen");
					finalCategorySet.add(othersCategory);
				}
			}

			if (accountList.size() == 1) {
				othersCategory.addAccount(accountList.iterator().next());
			} else if (category.getCategoryName().isEmpty()) {
				for (Account account : accountList) {
					othersCategory.addAccount(account);
				}
			} else {
				finalCategorySet.add(category);
			}
		}

		return finalCategorySet;
	}

	/**
	 * get an existing account or return new created account for the given position
	 * 
	 * @param accountList
	 * @param position
	 * @return
	 */
	private static Account getAccount(Set<Account> accountList, AccountPosition position) {
		String accountName = position.getAccountName();
		for (Account account : accountList) {
			if (account.getAccountName().equals(accountName)) {
				return account;
			}
		}
		return new Account(accountName);
	}

	/**
	 * Find an existing category for the given position
	 * 
	 * @param categorySet
	 *            : For now created categories
	 * @param position
	 *            : Current AccountPosition
	 * @return Found corresponding category (either INCOME category if amount is > 0 or a cost category
	 */
	private static Category getCategory(Set<Category> categorySet, AccountPosition position) {
		if (position.getBetrag() > 0) {
			return INCOME_CATEGORY;
		}
		for (Category category : categorySet) {
			if (category.getCategoryName().equals(position.getKreditor_Debitor())) {
				return category;
			}
		}
		return null;
	}

}
